home *** CD-ROM | disk | FTP | other *** search
/ Magazyn WWW 1999 July / www_07_1999.iso / prog / mac / alpha / alpha.hqx / Alpha ƒ / Help / AppleEvents Help < prev    next >
Text File  |  1999-04-14  |  16KB  |  430 lines

  1. ##############################################(nowrap)#############
  2.  Alpha AppleEvent Packages
  3.  
  4.                                    created: 4/9/98 {10:32:09 PM} 
  5.                                last update: 4/14/99 {2:10:26 PM} 
  6.                                    version: 1.2
  7.  Author: Jonathan Guyer
  8.  E-mail: <jguyer@his.com>
  9.     www: <http://www.his.com/~jguyer/>
  10.  
  11.  Copyright (c) 1998  Jonathan Guyer
  12.  
  13. ###################################################################
  14.  
  15. This package is free software; you can redistribute it and/or modify
  16. it under the terms of the GNU General Public License.
  17.  
  18. ###################################################################
  19.  
  20. Alpha's AEBuild command makes it (comparatively) easy to 
  21. interface with other applications, through the traumatic world of 
  22. AppleEvents (and Capture AE makes writing AE descriptors far easier 
  23. than it used to be, particulary for some inarticulate applications 
  24. (I won't mention any names, but a major offender rhymes with ╥Blinder╙)).  
  25. Using AEGizmos, one can build complicated event structures for 
  26. interaction with other programs. 
  27.  
  28. Alpha automatically processes AppleEvent replies from those 
  29. programs with AEPrint, which renders them reasonably 
  30. human-readable, but quite unwieldy to deal with, 
  31. programmatically.  Programmers wishing to work with AE from 
  32. within Alpha have been forced to write clumsy regexpen to attempt 
  33. to extract the elements of interest from event replies, but 
  34. because of the potential complexity of AE reply records, these 
  35. regexpen almost invariably fail to account for all contingencies.
  36.  
  37. To make it easier to work with AppleEvent replies (and, by 
  38. extension, to process events for which Alpha has been declared a 
  39. handler), I have written a suite of packages: aeparse.tcl, 
  40. aecoerce.tcl, and aebuild.tcl. The first two packages work in concert 
  41. to implement a reasonable facsimile of Jens Alfke's 
  42. ╥formidable-looking BNF grammar specification╙, parsing AEPrint 
  43. strings into Tcl-readable lists of lists. The third package 
  44. essentially replaces the routines in appleEvents.tcl with a more 
  45. consistently named set of routines. Stub routines remain in 
  46. appleEvents.tcl to map to the new format.
  47.  
  48. Given an ╥aevt\ansr{...}╙, a ╥GURL\GURL{...}╙, or some subset of an 
  49. AEGizmo string, you can parse to a list of lists; keyword searches 
  50. are then easy.
  51.  
  52. If you call:
  53.  
  54.     aeparse::event [AEBuild bladdity blah]
  55.  
  56. you get back a typed and tagged list of lists. If the reply 
  57. from [AEBuild bladdity blah] is:
  58.  
  59.     aevt\ansr{BLAH:5, blah:╥Blah?╙}
  60.  
  61. then aeparse::event will return
  62.  
  63.     reco {{BLAH {long 5}} {blah {TEXT Blah?}}}
  64.  
  65. All the extra tags may seem cumbersome, but the default behavior of 
  66. the routines is to strip them out. For instance: 
  67.  
  68.     aeparse::keywordValue blah [aeparse::event [AEBuild bladdity blah]]
  69.  
  70. will just return:
  71.  
  72.     Blah?
  73.  
  74. If you don't know in advance that the 'blah' keyword holds a string, 
  75. then aeparse::keywordValue takes an optional typed flag, so you'll get back
  76.  
  77.     TEXT Blah?
  78.  
  79. Since, for many event replies, the direct object is what's wanted, 
  80. there is a short-hand to replace
  81.  
  82.     aeparse::keywordValue ---- [aeparse::event [AEBuild bladdity blah]]
  83.  
  84. with 
  85.  
  86.     aebuild::result bladdity blah
  87.  
  88.  
  89. In the event of AppleEvent errors, aeparse::event automatically checks 
  90. for 'errn' and 'errs' tags and throws an appropriate error. The 
  91. array 'aeparse::errors' holds error messages to be used when no 
  92. 'errs' tag accompanies 'errn' (the Finder does this); see the 
  93. initialization code for aeparse for examples of the format.
  94.  
  95. In addition to parsing AE descriptor strings, calls to 
  96. aeparse::event automatically perform any type coercions that have 
  97. been declared with aecoerce::register. For example:
  98.  
  99.     aeparse::event {aevt\ansr{----:bool(╟01╚)}}
  100.     
  101. will not return
  102.  
  103.     reco {{---- {bool {hexd 01}}}}
  104.     
  105. but rather
  106.  
  107.     reco {{---- {bool 1}}}
  108.     
  109. so that
  110.  
  111.     aeparse::keywordValue "----" \
  112.         [aeparse::event {aevt\ansr{----:bool(╟01╚)}}]
  113.     
  114. just returns ╥1╙; no further processing is necessary.  
  115.  
  116. A more powerful example is seen in a rewrite of 
  117. mailboxPathIndex in eudoraMenu.tcl:
  118.  
  119.     proc mailboxPathIndex {ind} {
  120.         set res [objectProperty 'CSOm' euFS [mailboxByIndex $ind]]
  121.         return [extractPath $res]
  122.     }
  123.  
  124. 'res' will hold something like
  125.  
  126.     aevt\ansr{'----':fss (╟FFFD000001CC02496E00002F52FE002F52827FFF7FFF7FFF7F0001C70FC00000F90001D3F9547FFF7FFF01C95F5001D33C5E01D33BFC004120B401D33C4401D3CCCCCCCCCCCC╚)}
  127.     
  128. extractPath looks for anything between ╟ and ╚ and attempts to 
  129. coerce that from an 'fss ' to a path, returning
  130.  
  131.     documents:Eudora:HIS:In
  132.     
  133. This example happens to work, but some gross assumptions have 
  134. been made about the format of the returned AE descriptor string 
  135. and explicit coercions are needed after every AEBuild call. Using 
  136. the routines of this package, we can instead write:
  137.  
  138.     proc mailboxPathIndex {ind} {
  139.         set res [aeparse::event [objectProperty 'CSOm' euFS [mailboxByIndex $ind]]]
  140.         return [aeparse::keywordValue "----" $res]
  141.     }
  142.  
  143. In this case, 'res' holds
  144.  
  145.     reco {{---- {{fss } documents:Eudora:HIS:In}}}
  146.  
  147. Although the code is not any shorter, the coercion of 'fss ' has 
  148. been performed automatically (and not arbitrarily).  Although 
  149. this list of lists looks like a mess, it is easily processed by 
  150. aeparse::keywordValue, so you need not worry about its 
  151. internals.  We can simplify 'mailboxPathIndex' even further by 
  152. writing:
  153.  
  154.     proc mailboxPathIndex {ind} {
  155.         return [aebuild::result 'CSOm' core getd ---- \
  156.                     [propertyObject euFS [mailboxByIndex $ind]]]
  157.     }
  158.     
  159. or, better yet,
  160.  
  161.     proc mailboxPathIndex {ind} {
  162.         return [aebuild::objectProperty 'CSOm' euFS [mailboxByIndex $ind]]
  163.     }
  164.  
  165. CAVEAT: Because the AE descriptor string is being completely 
  166. parsed, aeparse::event can be rather slower than blind regexping. 
  167. The trade-off is that the results you obtain are much less 
  168. likely to be erroneous, especially for error conditions. I will be 
  169. looking for ways to speed things up, though.
  170. _________________________________________________________________
  171.  
  172. Cheater's Guide to AppleEvent Descriptors
  173. _________________________________________________________________
  174.  
  175. Until I found out about Capture AE (thanks Tom!), there was no simple 
  176. way to figure out how to write an AEDesc for some applications (I've 
  177. never learned anything useful from AETracker, but YMMV). Ironically, 
  178. the Finder is one of the hardest, at least in part because its 
  179. scripting model was developed concurrently with, and in some cases 
  180. before, the OSA architecture as a whole was developed. Determining 
  181. something as trivial as a list of the available disks which, in 
  182. AppleScript, is
  183.  
  184.     tell application "Finder" to get disks
  185.  
  186. can be an unholy nightmare to translate into AEGizmos. Fortunately, 
  187. if you activate Capture AE, execution of this script dumps
  188.  
  189.     Process("Finder").SendAE "core,getd,'----':obj {form:indx, want:type(cdis), seld:abso(╟616C6C20╚), from:'null'()}"
  190.  
  191. The '&inte' and '&timo' keys are not relevant to us, so this is 
  192. easily enough rendered in Tcl as
  193.  
  194.     AEBuild -r 'MACS' core getd ---- {obj {form:indx, want:type(cdis), seld:abso(╟616C6C20╚), from:'null'()}}
  195.  
  196. Although it works, "abso(╟616C6C20╚)" isn't very nice to look at.  A 
  197. quick pass with aecoerce::hexd:TEXT (or perusal of an ASCII chart) 
  198. reveals this is, reasonably enough, the identifier 'all ', so we 
  199. substitute that and make use of this suite of routines, yielding
  200.  
  201.     aebuild::result 'MACS' core getd ---- {obj {form:indx, want:type(cdis), seld:abso(all), from:'null'()}}
  202.  
  203. which... unfortunately... returns
  204.  
  205.     {reco {{want {type prop}} {from {null {}}} {form {type prop}} {seld {type sdsk}}}} {reco {{want {type cdis}} {from {null {}}} {form {type name}} {seld {TEXT catbert}}}} {reco {{want {type cdis}} {from {null {}}} {form {type name}} {seld {TEXT ratbert}}}}}
  206.  
  207. which is a parsing nightmare (note that, on top of everything else, the 
  208. Startup Disk is treated differently from everything else). Fortunately, 
  209. we can make the Finder do our work for us by using the 'rtyp' tag
  210.  
  211.     aebuild::result 'MACS' core getd rtyp TEXT ---- {obj {form:indx, want:type(cdis), seld:abso('all '), from:'null'()}}
  212.  
  213. which yields a manageable
  214.  
  215.     catbert: dogbert: ratbert: 
  216.  
  217. on my computer.
  218.  
  219.  
  220. Even with Capture AE, it's handy to be able to read 'aete' resources 
  221. (if for no other reason, to decipher what you just blindly copied 
  222. into your AEBuild statements). For this, Yuji Hachiya's 'aete' editor 
  223. for ResEdit is indispensible.
  224.  
  225.  
  226. If, for some reason, Capture AE is unavailable to you (redistribution 
  227. is prohibited, so WestCodeSoft could conceivably withdraw it), there 
  228. is, fortunately, a trick you can try: 
  229.  
  230.     1)    Enter the above AppleScript in the Script Editor and save it as 
  231.         a compiled script. 
  232.     2)    Open the script in a resource editor, open the 'scpt' resources, 
  233.         and open what will likely be the only 'scpt' resource there 
  234.         (if you have a 'scpt' resource editor installed, you'll want to 
  235.         be sure to open the resource as hexadecimal). 
  236.     3)    Look for the first occurence of the string 'MACS' (╟4D414353╚) 
  237.         and change this to 'ALFA' (╟414C4641╚). Ignore any explicit 
  238.         references to "Finder"; they don't matter. You've just changed the 
  239.         script to ask Alpha for a list of all disks. Alpha obviously doesn't 
  240.         know how to do this, but that's not the point. 
  241.     4)    Close and save your changes.
  242.     5)    Return to Alpha and write a dummy Tcl routine to intercept this event, 
  243.         such as 
  244.  
  245.             proc snoop {event} {}
  246.  
  247.         It needn't do any more than this. aeparse::event is decidedly not 
  248.         your friend for this task (try it if you don't believe me).
  249.     6)    Declare 'snoop' as an AppleEvent handler for the event you wish to 
  250.         examine:
  251.  
  252.             eventHandler core getd snoop
  253.  
  254.     7)    Place a trace on 'snoop'.
  255.     8)    Run your modified AppleScript applette from the Finder.
  256.     9)    Return to Alpha and dump traces. 
  257.  
  258. For the case above we obtain
  259.  
  260.     snoop 'core\getd{'----':obj {form:indx, want:type(cdis), seld:abso(╟616C6C20╚), from:'null'()}, &inte:cans, &timo:3600}' 
  261.     snoop OK: 
  262.  
  263. Although this probably seems like a lot of work, I assure you that 
  264. it's far preferable to the hunt-and-peck alternative. There's no 
  265. reason that this methodology won't work with other scriptable 
  266. applications, either, but I take no responsibility for the implosion 
  267. of your monitor.
  268.  
  269. _________________________________________________________________
  270.  
  271. Lexicon
  272. _________________________________________________________________
  273.  
  274. There are a plethora of routines in these packages, and the 
  275. majority of the parsing routines, in particular, will probably 
  276. never be called directly.  The ones most programmers will ever 
  277. have need to call are listed below.
  278.  
  279. Note: If you do have reason to parse some sub-string of an 
  280. AEDesc, keep in mind that, with the exception of aeparse::event, 
  281. all of the token and grammar parsers operate in place, i.e., they 
  282. are not passed a string, but the name of a string and, when 
  283. finished, the parsed material is removed from the start of the 
  284. string.
  285. _________________________________________________________________
  286.  
  287. AEParse
  288. _________________________________________________________________
  289.  
  290. NAME
  291.     aeparse::event - Parse a textual event record, as returned by AEPrint.
  292. SYNOPSIS
  293.     aeparse::event chars ?-all? ?-coerce coercions? 
  294.         ?-noCoerce noCoercions? 
  295. _________________________________________________________________
  296.  
  297. DESCRIPTION
  298.  
  299.     Optional parameters:
  300.     
  301.     -all: Return the entire parsed event structure, not just the AE 
  302.         descriptor record. The default behavior omits the class and the 
  303.         event. The reply from a call to AEBuild is always(?) an 
  304.         ╥aevt\ansr╙, but Alpha event handlers could potentially receive 
  305.         anything and may have use for this information.
  306.         
  307.     -coerce: Temporarily override (or supply) the specified type 
  308.         coercions. Takes a list of lists, each element of which is 
  309.         {'fromType' 'toType' 'coercionProc'}.
  310.         
  311.     -noCoerce: Do not perform the specified type coercions. This is 
  312.         useful, for instance, to prevent the automatic coercion of 
  313.         'alis's or 'fss 's to paths; this coercion is time consuming and 
  314.         may not always be of interest. Takes a list of lists, each 
  315.         element of which is {'fromType' 'toType'}. glob style 
  316.         wildcards can be used to block a whole family of coercions, 
  317.         e.g., ╥-noCoerce {{hexd *}}╙ will prevent all hexd coercions.
  318.         
  319. _________________________________________________________________
  320.  
  321. NAME
  322.     aeparse::keywordValue - Return value of keyword from AE record.
  323. SYNOPSIS
  324.     aeparse::keywordValue keyword record ?typed?
  325. _________________________________________________________________
  326.  
  327. DESCRIPTION
  328.  
  329.     Return the value of the specified keyword from a parsed 
  330.     AppleEvent record.
  331.  
  332.     Optional parameter:
  333.     
  334.     typed: Boolean flag determines whether the value is returned as a 
  335.         list {type value} or simply as value. Default is false.
  336.  
  337. _________________________________________________________________
  338.  
  339. AECoerce
  340. _________________________________________________________________
  341.  
  342. NAME
  343.     aecoerce::apply - coerce an AE value.
  344. SYNOPSIS
  345.     aecoerce::apply value type
  346. _________________________________________________________________
  347.  
  348. DESCRIPTION
  349.  
  350.     'value' is coerced to 'type'. 'value' must be a list of 
  351.     {'oldType' 'value'}. If a coercion from 'oldType' to 'type' has 
  352.     not been declared with aecoerce::register, or with the 
  353.     optional -coerce parameter to aeparse::event, then an error is 
  354.     thrown.
  355.  
  356. _________________________________________________________________
  357.  
  358. NAME
  359.     aecoerce::register - register a coercion procedure.
  360. SYNOPSIS
  361.     aecoerce::register from to proc
  362. _________________________________________________________________
  363.  
  364. DESCRIPTION
  365.  
  366.     Registers 'proc' to handle coercions from AE type 'from' to AE 
  367.     type 'to'. Proc must take a single argument of type 'from' and 
  368.     return a value of type 'to'. E.g., 
  369.     
  370.         aecoerce::register "hexd" "fss " specToPathName
  371.         
  372.     will handle the coercion of ╥fss (╟FFFD000001C╔CCCCC╚)╙ to 
  373.     {{fss } {documents:Eudora:HIS:In}}.
  374.     
  375. _________________________________________________________________
  376.  
  377. AEBuild
  378. _________________________________________________________________
  379.  
  380. NAME
  381.     aebuild::result - Build an AppleEvent and return the parsed 
  382.         direct object of its result.
  383. SYNOPSIS
  384.     aebuild::result args
  385. _________________________________________________________________
  386.  
  387. DESCRIPTION
  388.  
  389.     The arguments to this command are those of AEBuild. 
  390.     AEBuild's ╘-r╒ option to is not required, but is not harmful, 
  391.     either. The ╘-q╒ option is not meaningful in this context, 
  392.     and an ╥Unexpected end of format string╙ error will be thrown.
  393.     
  394.     There is no mechanism for overriding coercions with this call. If 
  395.     you wish to do that, you will need to use the long-hand
  396.     
  397.         aeparse::keywordValue ---- [aeparse::event [AEBuild -r ...] -coerce ...]
  398.  
  399. _________________________________________________________________
  400.  
  401. NAME
  402.     aebuild::fromParsed - Turn list of lists (generated by aeparse 
  403.         routines) into AEGizmo strings.
  404. SYNOPSIS
  405.     aebuild::fromParsed args
  406. _________________________________________________________________
  407.  
  408. DESCRIPTION
  409.  
  410.     The arguments to this command are those returned by aeparse::event 
  411.     (or a subset thereof). 
  412.  
  413.         aebuild::fromParsed [aeparse::event blah] 
  414.     
  415.     should be commutative (but there are surely many cases where this 
  416.     fails for now).
  417.  
  418. _________________________________________________________________
  419.  
  420. NAME
  421.     aebuild::objectProperty - Return specified property.
  422. SYNOPSIS
  423.     aebuild::objectProperty process property object
  424. _________________________________________________________________
  425.  
  426. DESCRIPTION
  427.  
  428.     Ask 'process' for 'property' of 'object'. There is no mechanism for 
  429.     overriding coercions with this call.
  430.